// ##########################################################################
// #                                                                        #
// #                              CLOUDCOMPARE                              #
// #                                                                        #
// #  This program is free software; you can redistribute it and/or modify  #
// #  it under the terms of the GNU General Public License as published by  #
// #  the Free Software Foundation; version 2 or later of the License.      #
// #                                                                        #
// #  This program is distributed in the hope that it will be useful,       #
// #  but WITHOUT ANY WARRANTY; without even the implied warranty of        #
// #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the          #
// #  GNU General Public License for more details.                          #
// #                                                                        #
// #          COPYRIGHT: EDF R&D / TELECOM ParisTech (ENST-TSI)             #
// #                                                                        #
// ##########################################################################

#ifndef CC_GLOBAL_SHIFT_MANAGER_HEADER
#define CC_GLOBAL_SHIFT_MANAGER_HEADER

// CCCoreLib
#include <CCGeom.h>

// local
#include "qCC_io.h"

// Qt
#include <QString>

// STL
#include <vector>

class ccHObject;

//! Helper class to handle big coordinates shift/scale (typically while loading entities)
class QCC_IO_LIB_API ccGlobalShiftManager
{
  public:
	//! Strategy to handle coordinates shift/scale
	enum Mode
	{
		NO_DIALOG,
		NO_DIALOG_AUTO_SHIFT,
		DIALOG_IF_NECESSARY,
		ALWAYS_DISPLAY_DIALOG
	};

	//! Handles coordinates shift/scale given the first 3D point and current related parameters
	static bool Handle(const CCVector3d& P,
	                   double            diagonal,
	                   Mode              mode,
	                   bool              useInputCoordinatesShiftIfPossible,
	                   CCVector3d&       coordinatesShift,
	                   bool*             _preserveCoordinateShift = nullptr,
	                   double*           _coordinatesScale        = nullptr,
	                   bool*             _applyAll                = nullptr);

	//! Returns whether a particular point (coordinates) is too big or not
	static bool NeedShift(const CCVector3d& P);
	//! Returns whether a particular point coordinate is too big or not
	static bool NeedShift(double d);
	//! Returns whether a particular dimension (e.g. diagonal) is too big or not
	static bool NeedRescale(double d);

	//! Suggests a shift for a given point expressed in global coordinate space
	static CCVector3d BestShift(const CCVector3d& P);
	//! Suggests a scale for a given dimension (e.g. diagonal) in global coordinate space
	static double BestScale(double d);

	//! Returns the max coordinate (absolute) value
	static double MaxCoordinateAbsValue()
	{
		return MAX_COORDINATE_ABS_VALUE;
	}
	//! Sets the max coordinate (absolute) value
	static void SetMaxCoordinateAbsValue(double value)
	{
		MAX_COORDINATE_ABS_VALUE = std::max(value, 1.0);
	}

	//! Returns max bounding-box diagonal
	static double MaxBoundgBoxDiagonal()
	{
		return MAX_DIAGONAL_LENGTH;
	}
	//! Sets the max bounding-box diagonal
	static void SetMaxBoundgBoxDiagonal(double value)
	{
		MAX_DIAGONAL_LENGTH = value;
	}

	//! Adds a new shift / scale couple
	static void StoreShift(const CCVector3d& shift, double scale, bool preserve = true);

  public: // Shift and scale info
	//! Shift and scale info
	struct ShiftInfo
	{
		CCVector3d shift;
		double     scale;
		QString    name;
		bool       preserve;

		//! Default constructor
		ShiftInfo(QString str = QString("unnamed"))
		    : shift(0, 0, 0)
		    , scale(1.0)
		    , name(str)
		    , preserve(true)
		{
		}
		//! Constructor from a vector and a scale value
		ShiftInfo(QString str, const CCVector3d& T, double s = 1.0)
		    : shift(T)
		    , scale(s)
		    , name(str)
		    , preserve(true)
		{
		}
	};

	//! Returns the default and last input shift/scale entries
	const static std::vector<ShiftInfo>& GetLast();

	//! Tries to load ShiftInfo data from a (text) file
	/** \param[in]  filename filename
	    \param[out] infos read information
	    \return success
	**/
	static bool LoadInfoFromFile(QString filename, std::vector<ShiftInfo>& infos);

  protected:
	// Max acceptable coordinate value
	static double MAX_COORDINATE_ABS_VALUE;

	// Max acceptable diagonal length
	static double MAX_DIAGONAL_LENGTH;
};

#endif
